#pragma once
#include <jsoncpp/json/json.h>
#include <iostream>
#include <string>

#include "../comm/Log.hpp"
#include "../comm/util.hpp"
#include "compile.hpp"
#include "runner.hpp"

namespace ns_compile_run
{
    using namespace ns_util;
    using namespace ns_compiler;
    using namespace ns_runner;
    class CompileAndRun
    {
    private:
        // 删除临时文件
        static void DelTempFile(const std::string& file_name)
        {
            std::string compile_err = PathUtil::Compile_error(file_name);
            if(FileUtil::IsFileExists(compile_err))
                unlink(compile_err.c_str());

            std::string src = PathUtil::Src(file_name);
            if(FileUtil::IsFileExists(src))
                unlink(src.c_str());

            std::string sin = PathUtil::Stdin(file_name);
            if(FileUtil::IsFileExists(sin))
                unlink(sin.c_str());

            std::string sout = PathUtil::Stdout(file_name);
            if(FileUtil::IsFileExists(sout))
                unlink(sout.c_str());

            std::string serr = PathUtil::Stderr(file_name);
            if(FileUtil::IsFileExists(serr))
                unlink(serr.c_str());
            
            std::string sexe = PathUtil::Exe(file_name);
            if(FileUtil::IsFileExists(sexe))
                unlink(sexe.c_str());
        }

        // 构建回复的 json 串
        static std::string HandleResult(int status, const std::string &reason, const std::string &out_info, const std::string &err_info)
        {
            Json::Value out_value;
            out_value["status"] = status;
            out_value["reason"] = reason;
            out_value["stdout"] = out_info;
            out_value["stderr"] = err_info;

            Json::FastWriter writer;
            return writer.write(out_value);
        }

        // 运行结束后根据返回结果获得原因
        static std::string GetInfoByRet(int ret)
        {
            switch(ret)
            {
            case 24: 
                return "CPU 超时";
            case 11:
                return "栈溢出(stack overflow)";
            case 8:
                return "浮点数错误";
            case 6:
                return "内存 超出限制";
            default:
                return "运行崩溃";
            }
        }

    public:
        /**********************
         * 输入：
         * code：用户提交的代码
         * input：用户的输入
         * cpu_limit：时间要求
         * mem_limit：空间要求
         *
         * 输出：
         * 必填
         * status : 状态码
         * reason : 请求结果 / 这个状态的原因
         * 选填
         * stdout : 输出
         * stderr : 错误
         *
         ***********************/
        // 完成 编译 并 运行的功能
        static void Start(const std::string &in_json, std::string *out_json)
        {
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();
            LOG(INFO, "cpu_limit: %d, mem_limit: %d\n", cpu_limit, mem_limit);

            if (code.size() == 0)
            {
                *out_json = HandleResult(-1, "用户提交的代码为空", "", "");

                return;
            }

            std::string file_name = FileUtil::UniqFileName(); // 获取一个唯一文件名

            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code)) // 形成 临时.cpp 文件
            {
                *out_json = HandleResult(-2, "发生了未知错误", "", "");

                DelTempFile(file_name);
                return;
            }

            if (!Compiler::Compile(file_name))
            {
                std::string _Compile_error;
                FileUtil::ReadFile(PathUtil::Compile_error(file_name), &_Compile_error, true);
                *out_json = HandleResult(-3, "编译失败", "", _Compile_error);

                DelTempFile(file_name);
                return;
            }

            int run_result = Runner::Run(file_name, cpu_limit, mem_limit);
            if(run_result < 0)
            {
                *out_json = HandleResult(-2, "发生了未知错误", "", "");
                DelTempFile(file_name);
                return;
            }
            else if(run_result > 0)
            {
                *out_json = HandleResult(run_result, GetInfoByRet(run_result), "", "");

                DelTempFile(file_name);
                return;
            }
            else  
            {
                std::string _stdout;
                std::string _stderr;

                FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
                FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr, true);

                *out_json = HandleResult(run_result, "运行成功", _stdout, _stderr);
                DelTempFile(file_name);
            }
        }
    };
}
